package cn.highedu.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;

public class HttpServletRequest {
    private Socket socket;
    /** 请求方式 */
    private String method;

    /** 请求路径，包含queryString 部分 */
    private String uri;

    /** 协议 */
    private String protocol;

    /** 请求头, 存储http请求中全部的请求头 */
    private HashMap<String, String> headers = new HashMap<>();

    /**
     * 请求路径，不包含queryString 部分
     */
    private String requestURI;
    /**
     * 查询字符串，uri 的 ？后面部分信息
     */
    private String queryString;

    /**
     * 存储全部的表单参数
     */
    private HashMap<String, String> parameters = new HashMap<>();


    public HttpServletRequest(Socket socket) throws IOException, BadRequestException{
        this.socket = socket;
        //解析请求行
        parseRequestLine();

        //解析请求头
        parseRequestHeaders();

        //解析请求消息体
        parseRequestBody();
    }

    /**
     * Post 请求方式 有Body，get请求没有Body
     * 1. 判断是否为Post请求，如果不是Post请求，就不处理
     *    Post请求的特点：
     *    a. Method = POST，
     *    b. Content-Type 是 application/x-www-form-urlencoded
     *    c. Content-Length
     */
    private void parseRequestBody() throws IOException{
        String contentType = getHeader("Content-Type");
        if ("POST".equals(method) &&
            "application/x-www-form-urlencoded".equals(contentType)){
            //处理解析表单
            int length = Integer.parseInt(getHeader("Content-Length"));
            //按照长度读取 请求流中的数据
            InputStream in = socket.getInputStream();
            byte[] bytes = new byte[length];
            in.read(bytes);
            String formData = new String(bytes, StandardCharsets.ISO_8859_1);
            //调用方法解析表单参数
            parseParameters(formData);
        }
    }


    /**
     * 从uri中继续get请求参数
     */
    private void parseUri() throws IOException{
        requestURI = uri;
        //如果uri中包含？才开始解析请求参数
        if (uri.contains("?")) {
            String[] parts = uri.split("\\?");
            requestURI = parts[0];
            queryString = parts[1];
            System.out.println("请求路径: "+ requestURI);
            System.out.println("查询字符串: "+ queryString);
            parseParameters(queryString);
        }
    }

    /**
     * 解析表单参数，可以处理get请求参数或者Post请求参数
     * @param formData 表单参数
     * @throws UnsupportedEncodingException 不会发生的异常
     */
    private void parseParameters(String formData) throws UnsupportedEncodingException {
        String[] parts = formData.split("&");
        for(String part: parts){
            System.out.println("解析参数："+part);
            String[] param = part.split("=");
            String name = param[0];
            String value = URLDecoder.decode(param[1],"UTF-8");
            parameters.put(name, value);
        }
    }

    public String getMethod() {
        return method;
    }
    public String getUri() {
        return uri;
    }
    public String getProtocol() {
        return protocol;
    }

    public String getRequestURI() {
        return requestURI;
    }

    public String getQueryString() {
        return queryString;
    }

    public String getParameter(String name){
        return parameters.get(name);
    }

    /**
     * 根据 请求头的名字，获取请求头的值
     * @param name 请求头的名字
     * @return 请求头的值
     */
    public String getHeader(String name){
        return headers.get(name);
    }

    /**
     * 从Socket中获取输入流，从流中读取一行
     * 解析请求行中的信息
     */
    private static final String SPACE = "\\s";
    private void parseRequestLine() throws IOException, BadRequestException{
        String requestLine = readLine();
        //根据HTTP协议描述，requestLine 有可能是空行!
        int n = 0;
        while (requestLine.isEmpty()){
            //跳过
            requestLine = readLine();
            if (n++ == 5){
                throw new BadRequestException("过多的空请求行！");
            }
        }
        //检查请求行是否符合规则
        String role = "(GET|POST|PUT|DELETE|HEAD|OPTIONS) ([^?#\\s]+)(\\?[^#\\s]*)? (HTTP\\/1\\.0|HTTP\\/1\\.1)";
        if (! requestLine.matches(role)){
            throw new BadRequestException("请求行不符合规则！");
        }

        String[] parts = requestLine.split(SPACE);
        method = parts[0];
        uri = parts[1];
        protocol = parts[2];
        System.out.println("解析请求行："+requestLine);
        System.out.println("method： "+method);
        System.out.println("uri： "+uri);
        System.out.println("protocol： "+protocol);

        //解析get请求参数
        parseUri();
    }

    /**
     * 解析请求头，将请求头信息，解析存储到HashMap中
     */
    private void parseRequestHeaders() throws IOException{
        String header;
        while (!(header = readLine()).isEmpty()){
            String[] parts = header.split(":\\s");
            String name = parts[0];
            String value = parts[1];
            headers.put(name, value);
            System.out.println("解析头：" + name + ": "+value);
        }
    }

    /**
     * 从Socket的流中读取一行数据
     * @return
     */
    private static final char CR = '\r';
    private static final char LF = '\n';
    private String readLine() throws IOException {
        InputStream in = socket.getInputStream();
        StringBuilder builder = new StringBuilder();
        char previous = 0;
        char current = 0;
        int b;
        while ((b=in.read())!=-1){
            current = (char) b;
            if (previous == CR && current == LF){
                break;
            }else if (current != CR && current != LF){
                builder.append(current);
            }
            previous = current;
        }
        return builder.toString();
    }
}










